第36章 文件操作
文件处理是程序与外部存储设备交互的重要方式,通过文件操作可以实现数据的持久化存储(如保存用户数据、日志记录)和批量数据处理。标准输入输出重定向则允许程序从文件读取输入或向文件写入输出,而无需修改代码逻辑。
36.1 文件处理的基本概念
36.1.1 文件的定义
按数据组织形式可分为两类:
- 文本文件:以ASCII/UTF-8字符存储,可直接用记事本打开(后缀
.txt)。 - 二进制文件:原始字节存储,无法直接文本阅读(如exe、图片、结构体数据文件
.bin)。
36.1.2 文件操作核心对象
- C语言:
FILE*文件指针,依赖<stdio.h> - C++语言:
ifstream/ofstream/fstream文件流,依赖<fstream>
36.1.3 文件操作通用三步
- 打开文件:建立程序与文件的连接;
- 读写数据;
- 关闭文件:刷新缓冲区,释放资源(必须执行,防止数据丢失)。
36.2 C语言文件处理
36.2.1 fopen 打开文件
函数原型
FILE *fopen(const char *filename, const char *mode);
- 返回值:打开成功返回文件指针,失败返回
NULL常用打开模式 | 模式 | 作用 | 文件类型 | | ---- | ---- | ---- | |r| 只读,文件必须存在 | 文本 | |w| 只写,不存在则创建,存在清空 | 文本 | |a| 追加写,文件末尾新增内容 | 文本 | |rb/wb/ab| 二进制只读/写/追加 | 二进制 | |r+/w+| 读写模式 | 文本 |
示例
#include <stdio.h>
int main(){
FILE *fp = fopen("data.txt", "r");
if(fp == NULL){
perror("文件打开失败");
return 1;
}
// 文件读写逻辑
fclose(fp); // 关闭文件
return 0;
}
36.2.2 fclose 关闭文件
原型:int fclose(FILE *stream);
成功返回0,失败返回EOF;不关闭会导致缓冲区数据未写入磁盘、资源泄漏。
36.2.3 文本文件读写
- 单字符读写
fgetc / fputc
int c;
// 读取所有字符直到文件末尾EOF
while((c = fgetc(fp)) != EOF){
putchar(c);
}
// 写入单个字符
fputc('A', fp);
- 整行读写
fgets / fputs
char buf[1024];
// 读取一行
fgets(buf, sizeof(buf), fp);
// 写入字符串,不会自动换行
fputs("Hello File\n", fp);
- 格式化读写
fscanf / fprintf
int x;
float pi;
fscanf(fp, "num=%d, val=%f", &x, &pi);
fprintf(fp, "数字:%d 小数:%.2f\n", x, pi);
36.2.4 二进制文件 fread / fwrite
原型
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t nmemb, FILE *stream);
示例:读写结构体
#include <stdio.h>
struct Student{
char name[20];
int age;
float score;
};
int main(){
FILE *fp = fopen("stu.bin", "wb");
Student s = {"Alice", 15, 90.5f};
fwrite(&s, sizeof(Student), 1, fp);
fclose(fp);
FILE *fp2 = fopen("stu.bin", "rb");
Student s2;
fread(&s2, sizeof(Student), 1, fp2);
printf("姓名:%s 年龄:%d 分数:%.1f", s2.name, s2.age, s2.score);
fclose(fp2);
return 0;
}
36.3 C++ 文件流操作
头文件 <fstream>
ifstream:文件输入(读)ofstream:文件输出(写)fstream:同时读写文件
36.3.1 打开与关闭文件
#include <fstream>
using namespace std;
int main(){
// 方式1:构造函数直接打开
ifstream inFile("data.txt");
if(!inFile.is_open()){
cerr << "打开失败" << endl;
return 1;
}
// 方式2:open方法
ofstream outFile;
outFile.open("out.txt", ios::out | ios::trunc);
inFile.close();
outFile.close();
return 0;
}
常用打开标记
| 标记 | 含义 |
|---|---|
| ios::in | 读文件 |
| ios::out | 写文件,默认清空 |
| ios::app | 追加写入 |
| ios::binary | 二进制模式 |
36.3.2 文本文件读写
// 写入
ofstream out("test.txt");
out << "姓名:张三" << endl;
out << 16;
out.close();
// 按符号读取
ifstream in("test.txt");
string name;
int age;
in >> name >> age;
// 读取整行
string line;
getline(in, line);
36.3.3 二进制 read 和 write
struct Student{
char name[20];
int age;
};
int main(){
ofstream out("stu.bin", ios::binary);
Student s = {"Charlie", 17};
out.write((char*)&s, sizeof(Student));
out.close();
ifstream in("stu.bin", ios::binary);
Student s2;
in.read((char*)&s2, sizeof(Student));
cout << s2.name;
return 0;
}
36.4 标准输入输出重定向
36.4.1 C语言 freopen
#include <stdio.h>
// 标准输入重定向到input.txt
freopen("input.txt", "r", stdin);
// 标准输出重定向到output.txt
freopen("output.txt", "w", stdout);
// 恢复控制台 Windows
freopen("CON", "r", stdin);
freopen("CON", "w", stdout);
36.4.2 C++ 缓冲区替换重定向
#include <iostream>
#include <fstream>
using namespace std;
int main(){
ifstream in("in.txt");
ofstream out("out.txt");
// 保存原始缓冲区
streambuf* cinBuf = cin.rdbuf();
streambuf* coutBuf = cout.rdbuf();
// 重定向
cin.rdbuf(in.rdbuf());
cout.rdbuf(out.rdbuf());
int x;
cin >> x;
cout << x * 2;
// 恢复标准流
cin.rdbuf(cinBuf);
cout.rdbuf(coutBuf);
in.close();
out.close();
return 0;
}
36.5 文件操作注意事项
- 打开后必须判断是否成功,避免空指针/空流访问;
- 使用完毕调用
fclose()/.close()释放资源; - 二进制读写不能混用
<<>>文本操作; - 重定向后务必恢复标准控制台流;
- 缓冲区数据只有关闭/刷新后才会写入磁盘。